﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using VMS.FTS.APPPUSH.Log;
using VMS.FTS.APPPUSH.VmsCenter;

namespace VMS.FTS.APPPUSH.WCFClients
{
    public class WCFClient : ILogable
    {
        Thread wcfHandlerThread;
        VmsCenterServiceClient client;
        
        #region | Constructor |
        public WCFClient()
        {
            // Init log tag
            LOG_TAG = this.GetType().Name;
            
            // WCF Service client
            client = new VmsCenterServiceClient();
            //client.Open();
            // Device of interest
            DOIList = new List<string>();
            // Command Spool Queue
            _dataSpool = new ObservableQueue<VmsCommand>();

            StatusTimer = new System.Timers.Timer(20000);
            StatusTimer.AutoReset = true;
            StatusTimer.Elapsed += StatusTimer_Elapsed;

            LOG("Init WCFClient successfully!", LOG_LEVEL.INFO);
        }

        public WCFClient(List<string> dList)
        {
            LOG_TAG = this.GetType().Name;

            // WCF Service client
           
            //client = new VmsCenter.VmsCenterServiceClient();
            //client.Connect("123");
              
            // Device of interest
            DOIList = dList;
            // Command Spool Queue
            _dataSpool = new ObservableQueue<VmsCommand>();

            StatusTimer = new System.Timers.Timer(60000);
            StatusTimer.AutoReset = true;
            StatusTimer.Elapsed += StatusTimer_Elapsed;
            
            LOG("Init WCFClient successfully!", LOG_LEVEL.INFO);
        }
        System.Timers.Timer StatusTimer;
        void StatusTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            VmsSystemCommand command = new VmsSystemCommand();
            command.VmsId = "FTown-01";
            command.CommandType = VmsSystemCommandEnum.COMMAND_GET_STATUS;
            DataSpool.Enqueue(command);
        }
        #endregion

        #region | Threading |
        bool isStart = false;
        /// <summary>
        /// Start wcf thread
        /// </summary>
        public void Start()
        {
            //InvokeGetPackageAsyncMethod(new List<string> { "VMS-15", "VMS-16" });
            //return;

            // check if thread exists
            if (wcfHandlerThread == null)
                wcfHandlerThread = new Thread(new ThreadStart(StartHandler));

            // close old thread
            if (wcfHandlerThread.IsAlive)
                Stop();

            // enable flag
            isStart = true;
            wcfHandlerThread.Start();
   
            // start get status timer
            StatusTimer.Start();
            LOG("WCFServices start successfully!", LOG_LEVEL.INFO);
        }

        /// <summary>
        /// call back function
        /// </summary>
        public void StartHandler()
        {
            if (DOIList.Count == 0) return;

            timeoutFlag = true;
            while (isStart)
            {
                Thread.Sleep(1000);
                try
                {      /*
                    if (client == null)
                    {
                        client = new VmsCenter.VmsCenterServiceClient();
                        client.Connect("123");
                    }
                    else */
                    {
                        using (client = new VmsCenter.VmsCenterServiceClient())
                        {
                            if (timeoutFlag)
                            {
                                //client.Open();
                                client.Connect("123");
                            }
                            timeoutFlag = false;

                            InvokeGetPackageAsyncMethod(DOIList);
                        }
                    }
                }
                catch (TimeoutException ex)
                {
                    // Timeout exception, 
                    LOG("Time out! retry...", LOG_LEVEL.ERROR);
                    if (client != null)
                        client.Close();
                    client = null;
                    timeoutFlag = true;
                }
                catch (Exception ex)
                {
                    LOG("Exception:\n" + ex.Message + "\nStack trace: " + ex.StackTrace, LOG_LEVEL.ERROR);
                    if (client != null)
                        client.Close();
                    client = null;
                    timeoutFlag = true;
                    break;
                }
            }
            LOG("Stop wcf loop", LOG_LEVEL.INFO);
        }

        public void Stop()
        {
            isStart = false;
            StatusTimer.Stop();
        }
        #endregion

        #region | Invoke Wcf service to get data |
        /// <summary>
        /// Get command releated to vms device
        /// </summary>
        /// <param name="listVms">VMD device need to get command</param>
        async void InvokeGetPackageAsyncMethod(List<string> listVms)
        {
            try
            {
                if (client == null)
                {
                    timeoutFlag = true;
                    return;
                }
                // get command from services
                LOG("Call get package async", LOG_LEVEL.DEBUG);
                var command = await client.GetPackageAsync("123",listVms.ToArray());
                // check valid command
                if (command != null)
                {
                    LOG("Got command OK", LOG_LEVEL.DEBUG);
                    // check if spool is null then create one
                    if (DataSpool == null)
                    {
                        LOG("Create command spool queue", LOG_LEVEL.DEBUG);
                        _dataSpool = new ObservableQueue<VmsCenter.VmsCommand>();
                    }
                    LOG("Received data for " + command.VmsId, LOG_LEVEL.DEBUG);
                    // Enqueue command to queue
                    DataSpool.Enqueue(command);
                }
                else
                {
                    // Save error to logging system
                    LOG("Error null command object", LOG_LEVEL.INFO);
                    if (client != null)
                        client.Close();
                    client = null;
                    //timeoutFlag = true;
                }
            }
            catch (TimeoutException ex)
            {
                // Timeout exception, 
                LOG("Time out! retry...", LOG_LEVEL.ERROR);
                if (client != null)
                    client.Close();
                client = null;
                timeoutFlag = true;
            }
            catch (Exception ex)
            {
                //isStart = false;
                LOG("Exception:\n" + ex.Message + "\nStack trace: " + ex.StackTrace, LOG_LEVEL.ERROR);
                if (client != null)
                    client.Close();
                client = null;
                timeoutFlag = true;
            }
        }
        static bool timeoutFlag = false;
        #endregion

        #region | Members |
        /// <summary>
        /// data spool private member
        /// </summary>
        ObservableQueue<VmsCenter.VmsCommand> _dataSpool;

        /// <summary>
        /// Read-only
        /// Spool that containts vmscommand from services
        /// </summary>
        public ObservableQueue<VmsCenter.VmsCommand> DataSpool
        {
            get { return _dataSpool; }
            set { _dataSpool = value; }
        }

        /// <summary>
        /// List device of interested.
        /// Wcf services only return command related to devices in this list.
        /// </summary>
        public List<string> DOIList;
        #endregion

        public bool SendInfo(VmsDeviceInfo globalVMSFTSAPPPUSHDEVICEVMSDeviceInfo)
        {
            return true;
            //client.SendStatus
        }

        public bool SendStatus(String vmsID,VmsDeviceStatus deviceStatus)
        {
            VmsDeviceStatus status = new VmsDeviceStatus();
            status.Connected = true;
            status.MemoryInfo = new VmsMemoryInfo();                                                                  
            status.MemoryInfo.Status = true;
            status.MemoryInfo.AvaibleSpace = new Random().Next(100);
            VmsSensor temp = new VmsSensor();
            temp.Name = "Temp";
            temp.Data = (20 + new Random().Next(20)) + " degree";
            status.Sensors = new VmsSensor[1];
            status.Sensors[0] = temp;

            using (client = new VmsCenter.VmsCenterServiceClient())
            {
                //client.Connect("123");
                bool ret = client.SendStatus("123", vmsID, status);
                client.Close();
                client = null;
                return ret;
            }
            return true;
        }

        internal VmsLayout RequestLayout(int layoutID)
        {
            using (client = new VmsCenter.VmsCenterServiceClient())
            {
                VmsLayout layout = client.GetLayout("123", layoutID);
                client.Close();
                client = null;
                return layout;
            }
            return null;
        }
    }

    /// <summary>
    /// Rewrite queue like OvervableCollection on .Net4.5
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ObservableQueue<T> : Queue<T>, INotifyCollectionChanged, INotifyPropertyChanged
    {
        public ObservableQueue()
        {
        }

        public ObservableQueue(IEnumerable<T> collection)
        {
            foreach (var item in collection)
                base.Enqueue(item);
        }

        public ObservableQueue(List<T> list)
        {
            foreach (var item in list)
                base.Enqueue(item);
        }


        public new virtual void Clear()
        {
            base.Clear();
            //this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        public new virtual T Dequeue()
        {
            var item = base.Dequeue();
            //this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
            return item;
        }

        public new virtual void Enqueue(T item)
        {
            base.Enqueue(item);
            this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
        }


        public virtual event NotifyCollectionChangedEventHandler CollectionChanged;


        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            this.RaiseCollectionChanged(e);
        }

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            this.RaisePropertyChanged(e);
        }


        protected virtual event PropertyChangedEventHandler PropertyChanged;


        private void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (this.CollectionChanged != null)
                this.CollectionChanged(this, e);
        }

        private void RaisePropertyChanged(PropertyChangedEventArgs e)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, e);
        }


        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
        {
            add { this.PropertyChanged += value; }
            remove { this.PropertyChanged -= value; }
        }
    }
}



